import 'dart:collection';

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:share_fit/app/controllers/base/base_controller.dart';
import 'package:share_fit/app/helper/db/ute_db_helper.dart';
import 'package:share_fit/app/helper/ext/tr_ext.dart';
import 'package:share_fit/app/models/home/date_type_enum.dart';
import 'package:share_fit/app/models/home/spo2_model.dart';
import 'package:share_fit/app/tools/locale_tool.dart';
import 'package:share_fit/app/tools/date_tool.dart';
import 'package:share_fit/generated/locales.g.dart';

import 'state.dart';

class Spo2Logic extends BaseController {
  final Spo2State state = Spo2State();

  changeDateType({type, int? selectedIndex}) {
    state.selectedDateType.value = type;
    state.dateTypeBarIndex = selectedIndex ?? 0;
    update(['spo2_date_type', 'date_type_bar']);

    if (type == DateType.year) {
      for (var month = 1; month <= 12; month++) {
        // state.dates.add('$month');
      }
    } else if (type == DateType.week) {
      List<DateTime> dts = type.getWeekDays;
      _queryInRange(dts.first, dts.last, true);
    } else if (type == DateType.month) {
      List<DateTime> dts = type.getMonthDays;
      _queryInRange(dts.first, dts.last, false);
    } else {
      // _queryTodayData(type.getToday);
      DateTime day = state.selectedDate;
      queryTodayInMinuteData(day);
    }
    update(['calendar_btn_icon']);
  }

  /// 右上角日历选择
  datePicker(dt) {
    if (dt != null) {
      state.selectedDate = dt;
      update(['calendar_btn_icon']);

      // _queryTodayData(dt);
      queryTodayInMinuteData(dt);
    }
  }

  String getCycleRadioTitle() {
    if (state.selectedDateType.value == DateType.day) {
      return LocaleKeys.spo2_day_cycle_ratio_title.ts;
    } else if (state.selectedDateType.value == DateType.week) {
      return LocaleKeys.spo2_week_cycle_ratio_title.ts;
    } else if (state.selectedDateType.value == DateType.month) {
      return LocaleKeys.spo2_month_cycle_ratio_title.ts;
    } else {
      return LocaleKeys.spo2_year_cycle_ratio_title.ts;
    }
  }

  Future<void> queryDataDetail(DateTime start, DateTime end) async {
    String dateStart = DateTool.getYMDStr(start);
    String dateEnd = DateTool.getYMDStr(end);
    UteDbHelper.getDB().then((db) => //
        db.spo2Dao.findDataDetail(getAddress(), dateStart, dateEnd).then((result) {
          if (result.isNotEmpty) {
            int max = result[0].oxygenValue!;
            int min = result[0].oxygenValue!;
            int avg = 0;

            for (var i = 0; i < result.length; i++) {
              int pv = result[i].oxygenValue!;

              avg += pv;

              // Checking for largest value in the list
              if (pv > max) {
                max = pv;
              }

              // Checking for smallest value in the list
              if (pv < min) {
                min = pv;
              }
            }

            state.dataDetail['avg_oxygen_value'] = '${avg ~/ result.length}%';
            state.dataDetail['min_oxygen_value'] = '$min%';
            state.dataDetail['max_oxygen_value'] = '$max%';
          } else {
            state.dataDetail['avg_oxygen_value'] = '--%';
            state.dataDetail['min_oxygen_value'] = '--%';
            state.dataDetail['max_oxygen_value'] = '--%';
          }

          update(['dataDetail']);
        }));
  }

  void fillList(list) {
    if (list.length == 1) {
      Spo2Summary temp = list.first;
      DateTime dt = DateTime.parse(temp.calendarTime);
      String start = DateTool.getYMDHMWithDash(DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute - 1, 0));
      list.insert(0, Spo2Summary(oxygenValue: 0, calendarTime: start, calendar: start.split(' ')[1]));
    }
  }

  Future<void> queryTodayInMinuteData(DateTime today) async {
    _updateDateRange(start: null, end: today);

    UteDbHelper.getDB().then((db) => //
        db.spo2Dao.findAllBy(getAddress(), DateTool.getYMDStr(today)).then((result) {
          List<Spo2Summary> summaryList = [];
          for (var res in result) {
            Spo2Summary summary = Spo2Summary.from(res);
            summary.calendar = res.calendarTime!.split(' ')[1];
            summaryList.add(summary);
          }

          fillList(summaryList);

          Spo2Summary hrs = Spo2Summary();
          hrs.oxygenAvgs = summaryList;
          state.spo2AvgList = hrs;

          update(['spo2_avg_list']);
        }));

    // 读取平均值、最大值、最小值
    queryDataDetail(today, today);

    getSpo2Summary(dt: today);
  }

  Future<void> _queryInRange(DateTime start, DateTime end, bool isWeek) async {
    _updateDateRange(start: start, end: end);

    final db = await UteDbHelper.getDB();
    List<Spo2Model> result = await db.spo2Dao.findInRange(getAddress(), DateTool.getYMDStr(start), DateTool.getYMDStr(end));

    List<Spo2Summary> summaryList = [];

    String langCode = LocaleTool.locale.split('_')[0];
    int days = end.difference(start).inDays;
    for (int i = 0; i <= days; i++) {
      DateTime temp = start.add(Duration(days: i));

      String calendar = isWeek ? DateFormat.E(langCode).format(temp) : DateTool.mdFormat(temp);

      List<Spo2Model> matched = result.where((e) => DateTime.parse(e.calendar!).isAtSameMomentAs(temp)).toList();
      int ov = matched.isNotEmpty ? matched[0].oxygenValue ?? 0 : 0;
      summaryList.add(Spo2Summary(calendar: calendar, calendarTime: DateFormat.yMMMd(langCode).format(temp), oxygenValue: ov));
    }

    Spo2Summary ss = Spo2Summary();
    ss.oxygenAvgs = summaryList;
    state.spo2AvgList = ss;
    update(['spo2_avg_list']);

    // 读取平均值、最大值、最小值
    queryDataDetail(start, end);

    getSpo2Summary();
  }

  void _updateDateRange({DateTime? start, required DateTime end}) {
    if (start == null) {
      state.dateRangeText = DateTool.ymdFormat(end);
    } else {
      state.dateRangeText = '${DateTool.ymdFormat(start)} ~ ${DateTool.ymdFormat(end)}';
    }
    update(['sleep_date_range']);
  }

  getSpo2Summary({DateTime? dt}) {
    if (DateType.day == state.selectedDateType.value) {
      UteDbHelper.getDB().then((db) => //
          db.spo2Dao.findLatestOne(getAddress(), DateTool.getYMDStr(dt ?? DateTime.now())).then((result) {
            state.summary = result == null ? '--' : '${result.oxygenValue.toString()}%';
            update(['spo2_summary']);
          }));
    } else {
      List<Spo2Summary> list = state.spo2AvgList.oxygenAvgs.where((element) => element.oxygenValue > 0).toList();
      if (list.isEmpty) {
        return '--';
      }
      double spo2Avg = list.map((e) => e.oxygenValue).reduce((value, element) => value + element).toDouble();
      spo2Avg = spo2Avg / list.length;
      state.summary = spo2Avg == 0 || spo2Avg.isNaN ? '--' : '${spo2Avg.round().toString().padLeft(3)}%';
      update(['spo2_summary']);
    }
  }

  @override
  String getRemotePath() {
    return '';
  }

  @override
  void initState() {
    // getSpo2SummaryData();

    // _queryTodayData(DateTime.now());
    queryTodayInMinuteData(DateTime.now());
    getSpo2Summary();
    _loadDateListOfRecord();
  }

  @override
  void onRemoteEvent(event, method) {
    // TODO: implement onRemoteEvent
  }

  loadEventForDay(DateTime day) {
    Map<DateTime, List<bool>> events = LinkedHashMap<DateTime, List<bool>>(
      equals: DateTool.isSameDay,
      hashCode: (key) => key.day * 1000000 + key.month * 10000 + key.year,
    )..addAll(state.dateListOfRecord);

    return events[day] ?? [];
  }

  /// 查找指定年份中有血氧记录的日期
  Future<void> _loadDateListOfRecord() async {
    DateTime now = DateTime.now();
    DateTime lastYear = DateUtils.addMonthsToMonthDate(now, -12);
    UteDbHelper.getDB().then((db) => //
        db.spo2Dao.findHasRecordDays(getAddress(), lastYear.year.toString(), now.year.toString()).then((result) {
          state.dateListOfRecord.clear();
          result.forEach((element) {
            state.dateListOfRecord.putIfAbsent(DateTime.parse(element), () => [true]);
          });
        }));
  }
}
